home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / BoxLayout.java < prev    next >
Text File  |  1998-06-30  |  15KB  |  397 lines

  1. /*
  2.  * @(#)BoxLayout.java    1.16 98/04/09
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21.  
  22. package com.sun.java.swing;
  23.  
  24. import java.awt.*;
  25. import java.io.Serializable;
  26. import java.io.PrintStream;
  27.  
  28. /**
  29.  * A layout manager that allows multiple components to be layed out either
  30.  * vertically or horizontally. The components will not wrap so, for 
  31.  * example, a vertical arrangement of components will stay vertically 
  32.  * arranged when the frame is resized. 
  33.  * <TABLE ALIGN="RIGHT" BORDER="0">
  34.  *    <TR>
  35.  *      <TD ALIGN="CENTER">
  36.  *         <P ALIGN="CENTER"><IMG SRC="doc-files/BoxLayout-1.gif" WIDTH="191" HEIGHT="201" ALIGN="BOTTOM" BORDER="0">
  37.  *      </TD>
  38.  *    </TR>
  39.  * </TABLE>
  40.  * <p>
  41.  * Nesting multiple panels with different combinations of horizontal and 
  42.  * vertical gives an effect similar to GridBagLayout, without the 
  43.  * complexity. The diagram shows two panels arranged horizontally, each 
  44.  * of which contains 3 components arranged vertically.
  45.  * <p>
  46.  * The Box container uses BoxLayout (unlike JPanel, which defaults to flow
  47.  * layout). You can nest multiple boxes and add components to them to get
  48.  * the arrangement you want.
  49.  * <p>
  50.  * The BoxLayout manager that places each of its managed components
  51.  * from left to right or from top to bottom.
  52.  * When you create a BoxLayout, you specify whether its major axis is 
  53.  * the X axis (which means left to right placement) or Y axis (top to 
  54.  * bottom placement). Components are arranged from left to right (or 
  55.  * top to bottom), in the same order as they were added to the container.
  56.  * <p>
  57.  * Instead of using BoxLayout directly, many programs use the Box class.
  58.  * The Box class provides a lightweight container that uses a BoxLayout.
  59.  * Box also provides handy methods to help you use BoxLayout well.
  60.  * <p>
  61.  * BoxLayout attempts to arrange components
  62.  * at their preferred widths (for left to right layout)
  63.  * or heights (for top to bottom layout).
  64.  * For a left to right layout,
  65.  * if not all the components are the same height,
  66.  * BoxLayout attempts to make all the components 
  67.  * as high as the highest component.
  68.  * If that's not possible for a particular component, 
  69.  * then BoxLayout aligns that component vertically,
  70.  * according to the component's Y alignment.
  71.  * By default, a component has an Y alignment of 0.5,
  72.  * which means that the vertical center of the component
  73.  * should have the same Y coordinate as 
  74.  * the vertical centers of other components with 0.5 Y alignment.
  75.  * <p>
  76.  * Similarly, for a vertical layout,
  77.  * BoxLayout attempts to make all components in the column
  78.  * as wide as the widest component;
  79.  * if that fails, it aligns them horizontally
  80.  * according to their X alignments.
  81.  * <p>
  82.  * Warning: serialized objects of this class will not be compatible with
  83.  * future swing releases.  The current serialization support is appropriate
  84.  * for short term storage or RMI between Swing1.0 applications.  It will
  85.  * not be possible to load serialized Swing1.0 objects with future releases
  86.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  87.  * baseline for the serialized form of Swing objects.
  88.  *
  89.  * @see Box
  90.  * @see Component#getAlignmentX
  91.  * @see Component#getAlignmentY
  92.  *
  93.  * @author   Timothy Prinzing
  94.  * @version  1.16 04/09/98
  95.  */
  96. public class BoxLayout implements LayoutManager2, Serializable {
  97.  
  98.     /**
  99.      * Specifies that components should be laid out left to right.
  100.      */
  101.     public static final int X_AXIS = 0;
  102.     
  103.     /**
  104.      * Specifies that components should be laid out top to buttom.
  105.      */
  106.     public static final int Y_AXIS = 1;
  107.  
  108.     /**
  109.      * Creates a layout manager that will lay out components either 
  110.      * left to right or
  111.      * top to bottom,
  112.      * as specified in the <code>axis</code> parameter.  
  113.      *
  114.      * @param target  the container that needs to be laid out
  115.      * @param axis  the axis to lay out components along.
  116.      *              For left-to-right layout, 
  117.      *              specify <code>BoxLayout.X_AXIS</code>;
  118.      *              for top-to-bottom layout, 
  119.      *              specify <code>BoxLayout.Y_AXIS</code>
  120.      *
  121.      * @exception AWTError  if the value of <code>axis</code> is invalid 
  122.      */
  123.     public BoxLayout(Container target, int axis) {
  124.         if (axis != X_AXIS && axis != Y_AXIS) {
  125.             throw new AWTError("Invalid axis");
  126.         }
  127.         this.axis = axis;
  128.         this.target = target;
  129.     }
  130.  
  131.     /**
  132.      * Constructs a BoxLayout that 
  133.      * produces debugging messages.
  134.      *
  135.      * @param target  the container that needs to be laid out
  136.      * @param axis  the axis to lay out components along; can be either
  137.      *              <code>BoxLayout.X_AXIS</code>
  138.      *              or <code>BoxLayout.Y_AXIS</code>
  139.      * @param dbg  the stream to which debugging messages should be sent,
  140.      *   null if none
  141.      */
  142.     BoxLayout(Container target, int axis, PrintStream dbg) {
  143.         this(target, axis);
  144.         this.dbg = dbg;
  145.     }
  146.  
  147.     /**
  148.      * Indicates that a child has changed its layout related information,
  149.      * and thus any cached calculations should be flushed.
  150.      *
  151.      * @param target  the affected container
  152.      *
  153.      * @exception AWTError  if the target isn't the container specified to the
  154.      *                      BoxLayout constructor
  155.      */
  156.     public void invalidateLayout(Container target) {
  157.         checkContainer(target);
  158.         xChildren = null;
  159.         yChildren = null;
  160.         xTotal = null;
  161.         yTotal = null;
  162.     }
  163.  
  164.     /**
  165.      * Not used by this class.
  166.      *
  167.      * @param name the name of the component
  168.      * @param comp the component
  169.      */
  170.     public void addLayoutComponent(String name, Component comp) {
  171.     }
  172.  
  173.     /**
  174.      * Not used by this class.
  175.      *
  176.      * @param comp the component
  177.      */
  178.     public void removeLayoutComponent(Component comp) {
  179.     }
  180.  
  181.     /**
  182.      * Not used by this class.
  183.      *
  184.      * @param comp the component
  185.      * @param constraints constraints
  186.      */
  187.     public void addLayoutComponent(Component comp, Object constraints) {
  188.     }
  189.  
  190.     /**
  191.      * Returns the preferred dimensions for this layout, given the components
  192.      * in the specified target container.
  193.      *
  194.      * @param target  the container that needs to be laid out
  195.      * @return the dimensions >= 0 && <= Integer.MAX_VALUE
  196.      * @exception AWTError  if the target isn't the container specified to the
  197.      *                      BoxLayout constructor
  198.      * @see Container
  199.      * @see #minimumLayoutSize
  200.      * @see #maximumLayoutSize
  201.      */
  202.     public Dimension preferredLayoutSize(Container target) {
  203.         checkContainer(target);
  204.         checkRequests();
  205.  
  206.         Dimension size = new Dimension(xTotal.preferred, yTotal.preferred);
  207.         Insets insets = target.getInsets();
  208.         size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  209.         size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  210.         return size;
  211.     }
  212.  
  213.     /**
  214.      * Returns the minimum dimensions needed to lay out the components
  215.      * contained in the specified target container.
  216.      *
  217.      * @param target  the container that needs to be laid out 
  218.      * @return the dimensions >= 0 && <= Integer.MAX_VALUE
  219.      * @exception AWTError  if the target isn't the container specified to the
  220.      *                      BoxLayout constructor
  221.      * @see #preferredLayoutSize
  222.      * @see #maximumLayoutSize
  223.      */
  224.     public Dimension minimumLayoutSize(Container target) {
  225.         checkContainer(target);
  226.         checkRequests();
  227.  
  228.         Dimension size = new Dimension(xTotal.minimum, yTotal.minimum);
  229.         Insets insets = target.getInsets();
  230.         size.width = (int) Math.min((long) + size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  231.         size.height = (int) Math.min((long) + size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  232.         return size;
  233.     }
  234.  
  235.     /**
  236.      * Returns the minimum dimensions needed to lay out the components
  237.      * contained in the specified target container.
  238.      *
  239.      * @param target  the container that needs to be laid out 
  240.      * @return the dimenions >= 0 && <= Integer.MAX_VALUE
  241.      * @exception AWTError  if the target isn't the container specified to the
  242.      *                      BoxLayout constructor
  243.      * @see #preferredLayoutSize
  244.      * @see #minimumLayoutSize
  245.      */
  246.     public Dimension maximumLayoutSize(Container target) {
  247.         checkContainer(target);
  248.         checkRequests();
  249.  
  250.         Dimension size = new Dimension(xTotal.maximum, yTotal.maximum);
  251.         Insets insets = target.getInsets();
  252.         size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  253.         size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  254.         return size;
  255.     }
  256.  
  257.     /**
  258.      * Returns the alignment along the X axis for the container.
  259.      * If the box is horizontal, the default
  260.      * alignment will be returned. Otherwise, the alignment needed
  261.      * to place the children along the X axis will be returned.
  262.      *
  263.      * @param target  the container
  264.      * @return the alignment >= 0.0f && <= 1.0f
  265.      * @exception AWTError  if the target isn't the container specified to the
  266.      *                      BoxLayout constructor
  267.      */
  268.     public float getLayoutAlignmentX(Container target) {
  269.         checkContainer(target);
  270.         checkRequests();
  271.         return xTotal.alignment;
  272.     }
  273.  
  274.     /**
  275.      * Returns the alignment along the Y axis for the container.
  276.      * If the box is vertical, the default
  277.      * alignment will be returned. Otherwise, the alignment needed
  278.      * to place the children along the Y axis will be returned.
  279.      *
  280.      * @param target  the container
  281.      * @return the alignment >= 0.0f && <= 1.0f
  282.      * @exception AWTError  if the target isn't the container specified to the
  283.      *                      BoxLayout constructor
  284.      */
  285.     public float getLayoutAlignmentY(Container target) {
  286.         checkContainer(target);
  287.         checkRequests();
  288.         return yTotal.alignment;
  289.     }
  290.  
  291.     /**
  292.      * Called by the AWT <!-- XXX CHECK! --> when the specified container
  293.      * needs to be laid out.
  294.      *
  295.      * @param target  the container to lay out
  296.      *
  297.      * @exception AWTError  if the target isn't the container specified to the
  298.      *                      BoxLayout constructor
  299.      */
  300.     public void layoutContainer(Container target) {
  301.         checkContainer(target);
  302.         checkRequests();
  303.         
  304.         int nChildren = target.getComponentCount();
  305.         int[] xOffsets = new int[nChildren];
  306.         int[] xSpans = new int[nChildren];
  307.         int[] yOffsets = new int[nChildren];
  308.         int[] ySpans = new int[nChildren];
  309.  
  310.         // determine the child placements
  311.         Dimension alloc = target.getSize();
  312.         Insets in = target.getInsets();
  313.         alloc.width -= in.left + in.right;
  314.         alloc.height -= in.top + in.bottom;
  315.         if (axis == X_AXIS) {
  316.             SizeRequirements.calculateTiledPositions(alloc.width, xTotal,
  317.                                                      xChildren, xOffsets,
  318.                                                      xSpans);
  319.             SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
  320.                                                        yChildren, yOffsets,
  321.                                                        ySpans);
  322.         } else {
  323.             SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
  324.                                                        xChildren, xOffsets,
  325.                                                        xSpans);
  326.             SizeRequirements.calculateTiledPositions(alloc.height, yTotal,
  327.                                                      yChildren, yOffsets,
  328.                                                      ySpans);
  329.         }
  330.  
  331.         // flush changes to the container
  332.         for (int i = 0; i < nChildren; i++) {
  333.             Component c = target.getComponent(i);
  334.             c.setBounds((int) Math.min((long) in.left + (long) xOffsets[i], Integer.MAX_VALUE),
  335.                         (int) Math.min((long) in.top + (long) yOffsets[i], Integer.MAX_VALUE),
  336.                         xSpans[i], ySpans[i]);
  337.  
  338.         }
  339.         if (dbg != null) {
  340.             for (int i = 0; i < nChildren; i++) {
  341.                 Component c = target.getComponent(i);
  342.                 dbg.println(c.toString());
  343.                 dbg.println("X: " + xChildren[i]);
  344.                 dbg.println("Y: " + yChildren[i]);
  345.             }
  346.         }
  347.             
  348.     }
  349.  
  350.     void checkContainer(Container target) {
  351.         if (this.target != target) {
  352.             throw new AWTError("BoxLayout can't be shared");
  353.         }
  354.     }
  355.     
  356.     void checkRequests() {
  357.         if (xChildren == null || yChildren == null) {
  358.             // The requests have been invalidated... recalculate
  359.             // the request information.
  360.             int n = target.getComponentCount();
  361.             xChildren = new SizeRequirements[n];
  362.             yChildren = new SizeRequirements[n];
  363.             for (int i = 0; i < n; i++) {
  364.                 Component c = target.getComponent(i);
  365.                 Dimension min = c.getMinimumSize();
  366.                 Dimension typ = c.getPreferredSize();
  367.                 Dimension max = c.getMaximumSize();
  368.                 xChildren[i] = new SizeRequirements(min.width, typ.width, 
  369.                                                     max.width, 
  370.                                                     c.getAlignmentX());
  371.                 yChildren[i] = new SizeRequirements(min.height, typ.height, 
  372.                                                     max.height, 
  373.                                                     c.getAlignmentY());
  374.             }
  375.             
  376.             if (axis == X_AXIS) {
  377.                 xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
  378.                 yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
  379.             } else {
  380.                 xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
  381.                 yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
  382.             }
  383.         }
  384.     }
  385.             
  386.     private int axis;
  387.     private Container target;
  388.  
  389.     private transient SizeRequirements[] xChildren;
  390.     private transient SizeRequirements[] yChildren;
  391.     private transient SizeRequirements xTotal;
  392.     private transient SizeRequirements yTotal;
  393.     
  394.     private transient PrintStream dbg;
  395. }
  396.  
  397.